package com.lancoo.ccas52.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lancoo.ccas52.entity.*;
import com.lancoo.ccas52.exception.BizException;
import com.lancoo.ccas52.mapper.*;
import com.lancoo.ccas52.pojo.common.GroupObject;
import com.lancoo.ccas52.pojo.common.PageInfo;
import com.lancoo.ccas52.pojo.constant.CommonConstants;
import com.lancoo.ccas52.pojo.vo.*;
import com.lancoo.ccas52.service.*;
import com.lancoo.ccas52.util.PagingUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * 课程 服务实现类
 * </p>
 *
 * @author quin.song
 * @since 2022-12-30
 */
@Service
@Slf4j
public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course> implements CourseService {

    @Resource
    private CourseMapper courseMapper;

    @Resource
    private SegmentMapper segmentMapper;
    @Resource
    private TeachingClassMapper teachingClassMapper;
    @Resource
    private CssPreSelectCourseMapper cssPreSelectCourseMapper;

    @Resource
    private PlanTeachingService planTeachingService;
    @Resource
    private SegmentService segmentService;

    @Resource
    private CourseApplyService courseApplyService;

    @Resource
    private SegmentApplyService segmentApplyService;

    @Resource
    private CourseWeekMapper courseWeekMapper;
    @Resource
    private CourseWeekService courseWeekService;
    @Resource
    private SegmentWeekService segmentWeekService;
    @Resource
    private TeachingClassWeekService teachingClassWeekService;
    @Resource
    private StudentService studentService;


    @Override
    public void syncCourse(Integer taskId, Set<Course> courses) {
        List<Course> insertList = new ArrayList<>();
        List<Course> courseList = this.list(new LambdaQueryWrapper<Course>().eq(Course::getTaskId, taskId));
        for (Course course : courses) {
            if (!courseList.contains(course)) {
                insertList.add(course);
            }
        }
        courseList.removeAll(courses);
        List<Long> deleteIds = courseList.stream().map(Course::getCourseId).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(deleteIds)) {
            this.removeBatchByIds(deleteIds);
        }
        if (CollUtil.isNotEmpty(insertList)) {
            courseMapper.addBatch(insertList);
        }
    }

    @Override
    public void syncSegment(Integer taskId, Set<Segment> syncSegment) {
        List<Segment> insertList = new ArrayList<>();
        List<Segment> segmentList = segmentService.list(new LambdaQueryWrapper<Segment>().eq(Segment::getTaskId, taskId));
        for (Segment segment : syncSegment) {
            if (!segmentList.contains(segment)) {
                insertList.add(segment);
            }
        }
        segmentList.removeAll(syncSegment);
        List<Long> deleteIds = segmentList.stream().map(Segment::getSegmentId).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(deleteIds)) {
            segmentService.removeBatchByIds(deleteIds);
        }
        if (CollUtil.isNotEmpty(insertList)) {
            segmentMapper.addBatch(insertList);
        }
    }


    @Override
    public List<CourseTypeDto> getCourseTypeByTaskId(Integer taskId, Integer flag) {
        List<CourseTypeDto> list = new ArrayList<>();
        if (flag.equals(1)) {
            list = courseMapper.getCourseTypeByTaskId(taskId);
        } else {
            list = segmentMapper.getSegmentTypeByTaskId(taskId);
        }
        return list;
    }


    @Override
    public ApplyStatistics<CourseApplyDto> getCourseDtoByConditions(Integer taskId, IPage page, Integer applyStatus, String courseTypeId, Integer courseNature, Integer majorProp, String collegeId, String keyWord) {
        ApplyStatistics<CourseApplyDto> applyStatistics = new ApplyStatistics<>();
        // 根据申请状态分组
        List<GroupObject<Number, Number>> group = courseMapper.getCourseApplyStatistics(taskId, applyStatus, courseTypeId, courseNature, majorProp, collegeId);
        for (GroupObject<Number, Number> object : group) {
            if (object.getField().intValue() == 1) {
                applyStatistics.setNormallyNum(object.getNum().longValue());
            } else if (object.getField().intValue() == 2) {
                applyStatistics.setChangingNum(object.getNum().longValue());
            } else if (object.getField().intValue() == 3) {
                applyStatistics.setPassedNum(object.getNum().longValue());
            } else if (object.getField().intValue() == 4) {
                applyStatistics.setRejectedNum(object.getNum().longValue());
            }
        }

        PageInfo<CourseApplyDto> pageInfo = new PageInfo<>();
        IPage<CourseApplyDto> courseDtos = courseMapper.getCourseByConditions(taskId, page, applyStatus, courseTypeId, courseNature, majorProp, collegeId, keyWord);
        pageInfo.setCurrentPage(courseDtos.getCurrent())
                .setPageSize(courseDtos.getSize())
                .setTotal(courseDtos.getTotal())
                .setPages(courseDtos.getPages())
                .setList(courseDtos.getRecords());

        applyStatistics.setPageInfo(pageInfo);
        return applyStatistics;
    }

    @Override
    public ApplyStatistics<SegmentDto> getSegmentDtoByConditions(Integer taskId, IPage page, Integer applyStatus, String segmentTypeId, String collegeId, String keyWord) {
        ApplyStatistics<SegmentDto> applyStatistics = new ApplyStatistics<>();
        // 根据申请状态分组
        List<GroupObject<Number, Number>> group = segmentMapper.getSegmentApplyStatistics(taskId, applyStatus, segmentTypeId, collegeId);
        for (GroupObject<Number, Number> object : group) {
            if (object.getField().intValue() == 1) {
                applyStatistics.setNormallyNum(object.getNum().longValue());
            } else if (object.getField().intValue() == 2) {
                applyStatistics.setChangingNum(object.getNum().longValue());
            } else if (object.getField().intValue() == 3) {
                applyStatistics.setPassedNum(object.getNum().longValue());
            } else if (object.getField().intValue() == 4) {
                applyStatistics.setRejectedNum(object.getNum().longValue());
            }
        }

        PageInfo<SegmentDto> pageInfo = new PageInfo<>();
        IPage<SegmentDto> segmentDtos = segmentMapper.getSegmentByConditions(taskId, page, applyStatus, segmentTypeId, collegeId, keyWord);
        pageInfo.setCurrentPage(segmentDtos.getCurrent())
                .setPageSize(segmentDtos.getSize())
                .setTotal(segmentDtos.getTotal())
                .setPages(segmentDtos.getPages())
                .setList(segmentDtos.getRecords());
        applyStatistics.setPageInfo(pageInfo);
        return applyStatistics;
    }

    @Override
    public CourseApply dealCourseApply(Integer taskId, String userId, String userName, CourseApplyInput courseApplyInput) {
        Course course = courseMapper.selectById(courseApplyInput.getCourseId());
        if (ObjUtil.isNull(course)) {
            throw new BizException("该课程不存在");
        }
        //申请实体类存储申请数据
        CourseApply courseApply = new CourseApply();
        courseApply.setCourseId(course.getCourseId())
                .setTaskId(taskId)
                .setDescription(courseApplyInput.getDescription())
                .setApplyStatus(2)
                .setOperationType(courseApplyInput.getOperationType())
                .setCreatedUserId(userId)
                .setCreatedUserName(userName);
        //默认一个课程只有一个申请记录
        LambdaUpdateWrapper<CourseApply> eq = new LambdaUpdateWrapper<CourseApply>().eq(CourseApply::getCourseId, course.getCourseId());
        //如果审核通过还继续申请的话  将审核通过记录更新到课程表.撤回的就不需要更新了
        if (courseApplyInput.getOperationType() != 4) {
            courseApplyService.lambdaQuery().eq(CourseApply::getCourseId, course.getCourseId()).eq(CourseApply::getApplyStatus, 3).oneOpt().ifPresent(courseApply1 -> {
                course.setLectureHour(courseApply1.getLectureHour())
                        .setExperimentalHour(courseApply1.getExperimentalHour())
                        .setComputerHour(courseApply1.getComputerHour())
                        .setOtherHour(courseApply1.getOtherHour())
                        .setIsEnable(1);
                courseMapper.updateById(course);
            });
        }
        switch (courseApplyInput.getOperationType()) {
            case 1:
            case 3:
                courseApply.setLectureHour(course.getLectureHour())
                        .setExperimentalHour(course.getExperimentalHour())
                        .setComputerHour(course.getComputerHour())
                        .setOtherHour(course.getOtherHour());
                courseApplyService.saveOrUpdate(courseApply, eq);
                break;
            case 2:
                courseApply.setLectureHour(courseApplyInput.getLectureHour())
                        .setExperimentalHour(courseApplyInput.getExperimentalHour())
                        .setComputerHour(courseApplyInput.getComputerHour())
                        .setOtherHour(courseApplyInput.getOtherHour());
                courseApplyService.saveOrUpdate(courseApply, eq);
                break;
            case 4:
                courseApply.setApplyStatus(0);
                courseApplyService.remove(eq);
                return courseApply;
            default:
                return null;
        }
        return ObjUtil.isNull(courseApply.getCourseApplyId()) ? courseApplyService.lambdaQuery().eq(CourseApply::getCourseId, course.getCourseId()).one() : courseApply;
    }

    @Override
    public SegmentApply dealSegmentApply(Integer taskId, String userId, String userName, SegmentApplyInput segmentApplyInput) {
        Segment segment = segmentMapper.selectById(segmentApplyInput.getSegmentId());
        if (ObjUtil.isNull(segment)) {
            throw new BizException("该环节不存在");
        }
        SegmentApply segmentApply = new SegmentApply();
        segmentApply.setSegmentId(segment.getSegmentId())
                .setTaskId(taskId)
                .setDescription(segmentApplyInput.getDescription())
                .setApplyStatus(2)
                .setOperationType(segmentApplyInput.getOperationType())
                .setCreatedUserId(userId)
                .setCreatedUserName(userName);
        //默认一个环节只有一个申请记录
        LambdaUpdateWrapper<SegmentApply> eq = new LambdaUpdateWrapper<SegmentApply>().eq(SegmentApply::getSegmentId, segment.getSegmentId());
        //如果审核通过还继续申请的话  将审核通过记录更新到环节表
        if (segmentApplyInput.getOperationType() != 4) {
            segmentApplyService.lambdaQuery().eq(SegmentApply::getSegmentId, segment.getSegmentId()).eq(SegmentApply::getApplyStatus, 3).oneOpt().ifPresent(segmentApply1 -> {
                segment.setWeekNum(segmentApply1.getWeekNum())
                        .setIsEnable(1);
                segmentMapper.updateById(segment);
            });
        }
        switch (segmentApplyInput.getOperationType()) {
            case 1:
            case 3:
                segmentApply.setWeekNum(segment.getWeekNum());
                segmentApplyService.saveOrUpdate(segmentApply, eq);
                break;
            case 2:
                segmentApply.setWeekNum(segmentApplyInput.getWeekNum());
                segmentApplyService.saveOrUpdate(segmentApply, eq);
                break;
            case 4:
                segmentApply.setApplyStatus(0);
                segmentApplyService.remove(eq);
                return segmentApply;
            default:
                return null;
        }
        return ObjUtil.isNull(segmentApply.getSegmentApplyId()) ? segmentApplyService.lambdaQuery().eq(SegmentApply::getSegmentId, segment.getSegmentId()).one() : segmentApply;
    }

    @Override
    public List<AddCourseSegment> getNotEnableCourseList(Integer taskId, String courseTypeId, Integer courseNature, Integer majorProp, String collegeId, String keyWord) {
        List<AddCourseSegment> resultList = new ArrayList<>();
        List<Course> list = courseMapper.getNotIsEnableApplyCourse(taskId, courseTypeId, courseNature, majorProp, collegeId, keyWord);
        list.forEach(course -> {
            StringBuilder string = new StringBuilder();
            string.append(course.getCourseName()).append("(").append(course.getCourseCode()).append(")-").append(course.getCollegeName())
                    .append("-").append(course.getCourseType()).append("-").append(course.getCourseNature().equals(1) ? "必修" : "选修");
            resultList.add(AddCourseSegment.builder().id(course.getCourseId()).name(string.toString()).baseId(course.getBaseCourseId()).build());
        });
        return resultList;
    }

    @Override
    public List<AddCourseSegment> getNotEnableSegmentList(Integer taskId, String collegeId, String keyWord) {
        List<AddCourseSegment> resultList = new ArrayList<>();
        List<Segment> list = segmentMapper.getNotIsEnableApplySegment(taskId, null, collegeId, keyWord);
        list.forEach(segment -> {
            StringBuilder string = new StringBuilder();
            string.append(segment.getSegmentName()).append("(").append(segment.getSegmentCode()).append(")-").append(segment.getCollegeName());
            resultList.add(AddCourseSegment.builder().id(segment.getSegmentId()).name(string.toString()).baseId(segment.getBaseSegmentId()).build());
        });
        return resultList;
    }

    @Override
    public boolean examineApply(Integer flag, Integer examine, Integer applyId, String reviewComment) {
        boolean sign = false;
        if (flag.equals(1)) {
            sign = courseApplyService.update(new LambdaUpdateWrapper<CourseApply>().eq(CourseApply::getCourseApplyId, applyId)
                    .set(CourseApply::getApplyStatus, examine.equals(1) ? 3 : 4)
                    .set(StrUtil.isNotBlank(reviewComment), CourseApply::getReviewComment, reviewComment)
            );
        } else {
            sign = segmentApplyService.update(new LambdaUpdateWrapper<SegmentApply>().eq(SegmentApply::getSegmentApplyId, applyId)
                    .set(SegmentApply::getApplyStatus, examine.equals(1) ? 3 : 4)
                    .set(StrUtil.isNotBlank(reviewComment), SegmentApply::getReviewComment, reviewComment));
        }
        return sign;
    }

    @Override
    public PublishStatistics getPublishStatistics(Integer taskId) {
        /*
        发布统计需要根据申请状态分别判断吗？通过的按照申请表显示，其他按照课程表显示？
        发布课程：<正常开课><变更审核中-修改、删除><已通过-增开><已驳回-修改、删除>
        增开：<已通过-增开>
        修改：<已通过-修改>
        停开：<已通过-删除>
         */
        PublishStatistics publishStatistics = new PublishStatistics();
        //课程统计
        PublishStatistics.Statistics courseCount = new PublishStatistics.Statistics();
        List<CourseApplyDto> courseApply = courseMapper.getCourseApply(taskId);

        courseApply.forEach(course -> {
            if (course.getApplyStatus().equals(3) && course.getOperationType().equals(2)) {
                courseCount.setModifyNum(courseCount.getModifyNum() + 1);
                courseCount.setReleaseNum(courseCount.getReleaseNum() + 1);
            } else if (course.getApplyStatus().equals(3) && course.getOperationType().equals(1)) {
                courseCount.setAddNum(courseCount.getAddNum() + 1);
                courseCount.setReleaseNum(courseCount.getReleaseNum() + 1);
            } else if (course.getApplyStatus().equals(3) && course.getOperationType().equals(3)) {
                courseCount.setStopNum(courseCount.getStopNum() + 1);
            } else if ((course.getApplyStatus().equals(1))
                    || (course.getApplyStatus().equals(2) && (course.getOperationType().equals(2) || course.getOperationType().equals(3)))
                    || (course.getApplyStatus().equals(3) && course.getOperationType().equals(1))
                    || (course.getApplyStatus().equals(4) && (course.getOperationType().equals(2) || course.getOperationType().equals(3)))) {
                courseCount.setReleaseNum(courseCount.getReleaseNum() + 1);
            }
        });
        publishStatistics.setCourseCount(courseCount);
        //环节统计
        PublishStatistics.Statistics segmentCount = new PublishStatistics.Statistics();
        List<SegmentDto> segmentApply = segmentMapper.getSegmentApply(taskId);
        segmentApply.forEach(segment -> {
            if (segment.getApplyStatus().equals(3) && segment.getOperationType().equals(2)) {
                segmentCount.setModifyNum(segmentCount.getModifyNum() + 1);
                segmentCount.setReleaseNum(segmentCount.getReleaseNum() + 1);
            } else if (segment.getApplyStatus().equals(3) && segment.getOperationType().equals(1)) {
                segmentCount.setAddNum(segmentCount.getAddNum() + 1);
                segmentCount.setReleaseNum(segmentCount.getReleaseNum() + 1);
            } else if (segment.getApplyStatus().equals(3) && segment.getOperationType().equals(3)) {
                segmentCount.setStopNum(segmentCount.getStopNum() + 1);
            } else if ((segment.getApplyStatus().equals(1))
                    || (segment.getApplyStatus().equals(2) && (segment.getOperationType().equals(2) || segment.getOperationType().equals(3)))
                    || (segment.getApplyStatus().equals(3) && segment.getOperationType().equals(1))
                    || (segment.getApplyStatus().equals(4) && (segment.getOperationType().equals(2) || segment.getOperationType().equals(3)))) {
                segmentCount.setReleaseNum(segmentCount.getReleaseNum() + 1);
            }
        });
        publishStatistics.setSegmentCount(segmentCount);

        return publishStatistics;

    }


    @Override
    public boolean checkPublishPlan(Integer taskId) {
        Page<CourseApplyDto> page = new Page<>(1, -1);
        Map<Integer, List<CourseApplyDto>> mapByApplyStatus = courseMapper.getCourseByConditions(taskId, page, null, null, null, null, null, null)
                .getRecords().stream().collect(Collectors.groupingBy(CourseApplyDto::getApplyStatus));
        //未审核课程
        String unreviewed = mapByApplyStatus.getOrDefault(2, ListUtil.empty()).stream().map(CourseApplyDto::getCourseName).collect(Collectors.joining("、"));
        if (StrUtil.isNotBlank(unreviewed)) {
            throw new BizException(5, "课程:" + unreviewed + "未审核，请审核好再进行发布");
        }
        //存在课程总学时为0 环节总周数为0的情况抛出提示。
        //正常开课 审核通过
        List<String> illegalCourseName = Stream.concat(mapByApplyStatus.getOrDefault(1, ListUtil.empty()).stream(), mapByApplyStatus.getOrDefault(3, ListUtil.empty()).stream())
                //停开的不需要判断
                .filter(a -> a.getOperationType() != 3)
                .filter(a -> a.getTotalHour() == 0).map(CourseApplyDto::getCourseName).collect(Collectors.toList());
        //驳回课程。判断非增开课程总学时
        List<Long> rejectCourseIds = mapByApplyStatus.getOrDefault(4, ListUtil.empty()).stream().filter(a -> a.getOperationType() != 1).map(CourseApplyDto::getCourseId).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(rejectCourseIds)) {
            illegalCourseName.addAll(this.listByIds(rejectCourseIds).stream()
                    .filter(a -> (a.getLectureHour() + a.getExperimentalHour() + a.getComputerHour() + a.getOtherHour()) == 0)
                    .map(Course::getCourseName).collect(Collectors.toList()));
        }
        if (CollectionUtil.isNotEmpty(illegalCourseName)) {
            throw new BizException(5, "课程:" + String.join("、", illegalCourseName) + "的总学时为0，请设置好该课程的参数再进行发布");
        }


        //环节
        Page<SegmentDto> pageSegment = new Page<>(1, -1);
        Map<Integer, List<SegmentDto>> mapSegmentByApplyStatus = segmentMapper.getSegmentByConditions(taskId, pageSegment, null, null, null, null)
                .getRecords().stream().collect(Collectors.groupingBy(SegmentDto::getApplyStatus));
        //未审核课程
        unreviewed = mapSegmentByApplyStatus.getOrDefault(2, ListUtil.empty()).stream().map(SegmentDto::getSegmentName).collect(Collectors.joining("、"));
        if (StrUtil.isNotBlank(unreviewed)) {
            throw new BizException(5, "环节:" + unreviewed + "未审核，请审核好再进行发布");
        }
        //存在课程总学时为0 环节总周数为0的情况抛出提示。
        //正常开课 审核通过
        illegalCourseName = Stream.concat(mapSegmentByApplyStatus.getOrDefault(1, ListUtil.empty()).stream(), mapSegmentByApplyStatus.getOrDefault(3, ListUtil.empty()).stream())
                .filter(a -> a.getOperationType() != 3)
                .filter(a -> a.getWeekNum() == 0).map(SegmentDto::getSegmentName).collect(Collectors.toList());
        //驳回课程
        List<Long> rejectSegmentIds = mapSegmentByApplyStatus.getOrDefault(4, ListUtil.empty()).stream().filter(a -> a.getOperationType() != 1).map(SegmentDto::getSegmentId).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(rejectSegmentIds)) {
            illegalCourseName.addAll(segmentService.listByIds(rejectSegmentIds).stream().filter(a -> a.getWeekNum() == 0).map(Segment::getSegmentName).collect(Collectors.toList()));
        }
        if (CollectionUtil.isNotEmpty(illegalCourseName)) {
            throw new BizException(5, "环节:" + String.join("、", illegalCourseName) + "的总周数为0，请设置好该课程的参数再进行发布");
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean publishPlan(Integer taskId) {
        List<Course> updateCourseList = new ArrayList<>();
        List<Segment> updateSegmentList = new ArrayList<>();
        //课程
        List<CourseApply> courseApplyList = courseApplyService.list(new LambdaQueryWrapper<CourseApply>().eq(CourseApply::getTaskId, taskId)
                .eq(CourseApply::getApplyStatus, 3));
        for (CourseApply courseApply : courseApplyList) {
            Course course = new Course();
            course.setCourseId(courseApply.getCourseId());
            if (courseApply.getOperationType().equals(1)) {
                course.setIsEnable(1);
                updateCourseList.add(course);
            } else if (courseApply.getOperationType().equals(2)) {
                course.setLectureHour(courseApply.getLectureHour())
                        .setExperimentalHour(courseApply.getExperimentalHour())
                        .setComputerHour(courseApply.getComputerHour())
                        .setOtherHour(courseApply.getOtherHour())
                        .setIsEnable(1);
                updateCourseList.add(course);
            } else if (courseApply.getOperationType().equals(3)) {
                course.setIsEnable(2);
                updateCourseList.add(course);
            }
        }
        //环节
        List<SegmentApply> segmentApplyList = segmentApplyService.list(new LambdaQueryWrapper<SegmentApply>().eq(SegmentApply::getTaskId, taskId)
                .eq(SegmentApply::getApplyStatus, 3));
        for (SegmentApply segmentApply : segmentApplyList) {
            Segment segment = new Segment();
            segment.setSegmentId(segmentApply.getSegmentId());
            if (segmentApply.getOperationType().equals(1)) {
                segment.setIsEnable(1);
                updateSegmentList.add(segment);
            } else if (segmentApply.getOperationType().equals(2)) {
                segment.setWeekNum(segmentApply.getWeekNum())
                        .setIsEnable(1);
                updateSegmentList.add(segment);
            } else if (segmentApply.getOperationType().equals(3)) {
                segment.setIsEnable(2);
                updateSegmentList.add(segment);
            }
        }
        //更新课程修读性质字段
        courseMapper.getCoursePlan(taskId).stream()
                .filter(coursePlanDto -> coursePlanDto.getCourseId() != null)
                .collect(Collectors.groupingBy(CoursePlanDto::getCourseId))
                .forEach((courseId, planList) -> {
                    long distinctStudyNatureCount = planList.stream().map(CoursePlanDto::getStudyNature).distinct().count();
                    int studyNature = (distinctStudyNatureCount == 2) ? 3 : planList.get(0).getStudyNature();
                    Optional<Course> existingCourse = updateCourseList.stream()
                            .filter(existing -> existing.getCourseId().equals(courseId))
                            .findFirst();
                    if (existingCourse.isPresent()) {
                        existingCourse.get().setStudyNature(studyNature);
                    } else {
                        Course course = new Course();
                        course.setStudyNature(studyNature);
                        course.setCourseId(courseId);
                        updateCourseList.add(course);
                    }
                });
        // 更新环节修读性质字段
        segmentMapper.getSegmentPlan(taskId).stream()
                .filter(segmentPlanDto -> segmentPlanDto.getSegmentId() != null)
                .collect(Collectors.groupingBy(SegmentPlanDto::getSegmentId))
                .forEach((segmentId, planList) -> {
                    long distinctStudyNatureCount = planList.stream().map(SegmentPlanDto::getStudyNature).distinct().count();
                    int studyNature = (distinctStudyNatureCount == 2) ? 3 : planList.get(0).getStudyNature();
                    Optional<Segment> existingSegment = updateSegmentList.stream()
                            .filter(existing -> existing.getSegmentId().equals(segmentId))
                            .findFirst();
                    if (existingSegment.isPresent()) {
                        existingSegment.get().setStudyNature(studyNature);
                    } else {
                        Segment segment = new Segment();
                        segment.setStudyNature(studyNature);
                        segment.setSegmentId(segmentId);
                        updateSegmentList.add(segment);
                    }
                });

        this.updateBatchById(updateCourseList);
        segmentService.updateBatchById(updateSegmentList);
        return true;
    }

    @Override
    public PageInfo<CoursePlanDto> getCoursePlanAndCourseWeek(Integer taskId, IPage page, Integer studyNature, String courseTypeId, Integer courseNature, Integer majorProp, String collegeId, String keyWord, Integer uniqueShiftSign, Integer state) {
        IPage<CoursePlanDto> coursePlanPage = courseMapper.getCoursePlanAndCourseWeek(taskId, page, studyNature, courseTypeId, courseNature, majorProp, collegeId, keyWord, uniqueShiftSign, state);
        List<CoursePlanDto> coursePlanList = coursePlanPage.getRecords();
        if (CollUtil.isEmpty(coursePlanList)) {
            return PagingUtil.formatPageResult(coursePlanPage);
        }
        List<Long> courseIds = coursePlanList.stream().map(CoursePlanDto::getCourseId).collect(Collectors.toList());
        //填充设置得周次相关信息
        Map<String, List<CourseWeek>> weekMap = courseWeekMapper.selectAllByCourseId(courseIds)
                .stream().collect(Collectors.groupingBy(o -> o.getCourseId() + "-" + o.getStudyNature()));
        coursePlanList.forEach(a -> {
            a.setCourseWeeks(weekMap.get(a.getCourseId() + "-" + a.getStudyNature()));
        });
        coursePlanPage.setRecords(coursePlanList);
        return PagingUtil.formatPageResult(coursePlanPage);
    }

    @Override
    public CourseWeek setCourseWeek(WeekInput weekInput) {
        CourseWeek courseWeek = BeanUtil.copyProperties(weekInput, CourseWeek.class);
        //saveOrUpdate 会发生死锁
        courseWeekMapper.insertSelective(courseWeek);
        //修改其相关教学班参数.现在只涉及到修改，因为设置教学班只显示已设置参数的课程所以不存在没有参数的教学班
        List<Long> teachingClassIds = teachingClassMapper.selectList(new LambdaQueryWrapper<TeachingClass>()
                .eq(TeachingClass::getFlag, 1)
                .eq(TeachingClass::getCourseId, weekInput.getCourseId())
                .eq(TeachingClass::getStudyNature, weekInput.getStudyNature())
                .ne(TeachingClass::getTeachingClassType, 3)).stream().map(TeachingClass::getTeachingClassId).collect(Collectors.toList());
        if (CollUtil.isEmpty(teachingClassIds)) {
            return courseWeek;
        }
        //更新教学班周次参数
        teachingClassWeekService.lambdaUpdate().in(TeachingClassWeek::getTeachingClassId, teachingClassIds)
                .eq(TeachingClassWeek::getHourType, weekInput.getHourType())
                .set(TeachingClassWeek::getWeek, weekInput.getWeek())
                .set(TeachingClassWeek::getWeekNum, weekInput.getWeekNum())
                .set(TeachingClassWeek::getConnectSection, weekInput.getConnectSection())
                .set(TeachingClassWeek::getConnectNumber, weekInput.getConnectNumber())
                .set(TeachingClassWeek::getRoomType, weekInput.getRoomType())
                .set(weekInput.getUpdateRoomId(), TeachingClassWeek::getRoomId, null)
                .update();
        //新增教学班周次参数。须遍历教学班参数，筛选出没有设置的教学班
        return courseWeek;
    }

    @Override
    public boolean isExistRoom(Long courseId, Integer studyNature,Integer hourType) {
        //获取指定课程 对应教学班参数
        List<TeachingClassWeek> existRoomTeachingClassWeek = teachingClassMapper.getExistRoomTeachingClassWeek(courseId, studyNature,hourType);
        return CollUtil.isNotEmpty(existRoomTeachingClassWeek);
    }


    @Override
    public Integer oddEvenWeekStatistics(Integer taskId) {
        List<GroupObject<Number, Number>> group = courseWeekMapper.oddEvenWeekStatistics(taskId);
        long oddNum = group.stream().filter(a -> a.getField().equals(1))
                .findFirst()
                .map(b -> b.getNum().longValue()).orElse(0L);
        long evenNum = group.stream().filter(a -> a.getField().equals(2))
                .findFirst()
                .map(b -> b.getNum().longValue()).orElse(0L);
        return oddNum <= evenNum ? 1 : 2;
    }

    @Override
    public TeachingClassWeek setTeachingClassWeek(TeachingClassWeek teachingClassWeek) {
        teachingClassWeekService.saveOrUpdate(teachingClassWeek, new LambdaUpdateWrapper<TeachingClassWeek>()
                .eq(TeachingClassWeek::getTeachingClassId, teachingClassWeek.getTeachingClassId())
                .eq(TeachingClassWeek::getHourType, teachingClassWeek.getHourType()));
        return teachingClassWeek;

    }

    @Override
    public void initTeachingClassWeek(List<TeachingClass> teachingClassList) {
        //多个教学班不同课程初始化教学班参数
        if (CollUtil.isNotEmpty(teachingClassList)) {
            //待新增教学班参数
            List<TeachingClassWeek> allTeachingClassWeeks = new ArrayList<>();
            //根据课程-修读性质分组
            teachingClassList.stream().collect(Collectors.groupingBy(o -> o.getCourseId() + "-" + o.getStudyNature())).forEach((courseId, list) -> {
                TeachingClass teachingClass = list.get(0);
                if (teachingClass.getFlag() == 1) {
                    //课程
                    List<CourseWeek> courseWeekList = courseWeekService.list(new LambdaQueryWrapper<CourseWeek>()
                            .eq(CourseWeek::getStudyNature, teachingClass.getStudyNature())
                            .eq(CourseWeek::getCourseId, teachingClass.getCourseId()));
                    if (CollUtil.isNotEmpty(courseWeekList)) {
                        list.forEach(a -> {
                            List<TeachingClassWeek> teachingClassWeeks = courseWeekList.stream()
                                    .map(courseWeek -> BeanUtil.toBean(courseWeek, TeachingClassWeek.class, CopyOptions.create().setIgnoreProperties("id")))
                                    .peek(b -> b.setTeachingClassId(a.getTeachingClassId()))
                                    .peek(b -> assignRoomId(b, a))
                                    .collect(Collectors.toList());
                            allTeachingClassWeeks.addAll(teachingClassWeeks);
                        });
                    }
                } else {
                    //环节 按理说环节只有一条数据
                    SegmentWeek segmentWeek = segmentWeekService.getOne(new LambdaQueryWrapper<SegmentWeek>()
                            .eq(SegmentWeek::getStudyNature, teachingClass.getStudyNature())
                            .eq(SegmentWeek::getSegmentId, teachingClass.getCourseId()), false);
                    if (ObjUtil.isNotNull(segmentWeek)) {
                        teachingClassList.forEach(a -> {
                            TeachingClassWeek teachingClassWeek = TeachingClassWeek.builder()
                                    .teachingClassId(a.getTeachingClassId())
                                    .week(segmentWeek.getWeek())
                                    .hourType(0).build();
                            allTeachingClassWeeks.add(teachingClassWeek);
                        });
                    }
                }
            });

            teachingClassWeekService.saveBatch(allTeachingClassWeeks);
        }
    }

    @Override
    public void updateTeachingClassWeek(List<TeachingClassInput> teachingClassInputs) {
        List<TeachingClass> teachingClassList = BeanUtil.copyToList(teachingClassInputs, TeachingClass.class);
        List<Long> teachingClassIds = teachingClassList.stream().map(TeachingClass::getTeachingClassId).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(teachingClassIds)) {
            List<TeachingClassWeek> teachingClassWeeks = teachingClassWeekService.list(new LambdaQueryWrapper<TeachingClassWeek>()
                    .in(TeachingClassWeek::getTeachingClassId, teachingClassIds));
            teachingClassWeeks.forEach(a -> {
                TeachingClass teachingClass = teachingClassList.stream().filter(b -> b.getTeachingClassId().equals(a.getTeachingClassId())).findFirst().orElse(null);
                if (ObjUtil.isNotNull(teachingClass)) {
                    assignRoomId(a, teachingClass);
                }
            });
            teachingClassWeekService.updateBatchById(teachingClassWeeks);
        }
    }

    /**
     * 为教学班参数赋值教室id
     * @param teachingClassWeek
     * @param teachingClass
     */
    private void assignRoomId(TeachingClassWeek teachingClassWeek, TeachingClass teachingClass) {
        switch (teachingClassWeek.getHourType()) {
            case CommonConstants.LECTURE:
                teachingClassWeek.setRoomId(teachingClass.getLectureRoomId());
                break;
            case CommonConstants.EXPERIMENTAL:
                teachingClassWeek.setRoomId(teachingClass.getExperimentalRoomId());
                break;
            case CommonConstants.COMPUTER:
                teachingClassWeek.setRoomId(teachingClass.getComputerRoomId());
                break;
            case CommonConstants.OTHER:
                teachingClassWeek.setRoomId(teachingClass.getOtherRoomId());
                break;
            default:
                teachingClassWeek.setRoomId(null);
        }
    }


    @Override
    public SegmentWeek setSegmentWeek(SegmentWeek segmentWeek) {
        segmentWeekService.saveOrUpdate(segmentWeek, new LambdaUpdateWrapper<SegmentWeek>()
                .eq(SegmentWeek::getStudyNature, segmentWeek.getStudyNature())
                .eq(SegmentWeek::getSegmentId, segmentWeek.getSegmentId()));
        //修改其相关教学班参数
        List<TeachingClass> teachingClassList = teachingClassMapper.getTeachingClassByCourseId(2, segmentWeek.getSegmentId(), segmentWeek.getStudyNature(), 4);
        List<Long> teachingClassIds = teachingClassList.stream().map(TeachingClass::getTeachingClassId).collect(Collectors.toList());
        teachingClassIds.forEach(a -> {
            TeachingClassWeek teachingClassWeek = TeachingClassWeek.builder()
                    .teachingClassId(a)
                    .week(segmentWeek.getWeek())
                    .hourType(segmentWeek.getHourType())
                    .build();
            teachingClassWeekService.saveOrUpdate(teachingClassWeek, new LambdaUpdateWrapper<TeachingClassWeek>()
                    .eq(TeachingClassWeek::getTeachingClassId, a));
        });
        return segmentWeek;
    }

    @Override
    public PageInfo<CoursePlanDto> getCoursePlanAndTeachingClass(Integer taskId, IPage page, Integer studyNature, String courseTypeId, Integer courseNature, Integer majorProp, String collegeId, String keyWord, Integer state, Integer teachingClassType, Integer uniqueShiftSign) {
        IPage<CoursePlanDto> coursePlanPage = courseMapper.getCoursePlanAndTeachingClass(taskId, page, studyNature, courseTypeId, courseNature, majorProp, collegeId, keyWord, state, teachingClassType, uniqueShiftSign);
        //获取全部预选课程
        Set<String> preCourse = cssPreSelectCourseMapper.selectList(new LambdaQueryWrapper<CssPreSelectCourse>().eq(CssPreSelectCourse::getTaskId, taskId))
                .stream().map(a -> a.getCourseId() + "-" + a.getStudyNature()).collect(Collectors.toSet());
        //填充上课人数，预计效率很慢。
        for (CoursePlanDto record : coursePlanPage.getRecords()) {
            int teachingPlanStu = planTeachingService.getStudentNumByCourseAndNature(1, record.getCourseId(), record.getStudyNature(), null).size();
            record.setStudentNumPlan(teachingPlanStu);
            record.setStudentNum(teachingPlanStu);
            //判断是否有预选情况
            if (preCourse.contains(record.getCourseId() + "-" + record.getStudyNature())) {
                record.setIsPreSelect(1);
                record.setStudentNumPre(studentService.getStudentCountByCourse(1, record.getCourseId(), record.getStudyNature(), 3));
            } else {
                record.setIsPreSelect(2);
            }
        }

        return PagingUtil.formatPageResult(coursePlanPage);

    }

    @Override
    public PageInfo<SegmentPlanDto> getSegmentPlanAndTeachingClass(Integer taskId, IPage page, Integer studyNature, String segmentTypeId, String collegeId, String keyWord, Integer state) {
        IPage<SegmentPlanDto> segmentPlanPage = segmentMapper.getSegmentPlanAndTeachingClass(taskId, page, studyNature, segmentTypeId, collegeId, keyWord, state);
        //填充上课人数，
        for (SegmentPlanDto record : segmentPlanPage.getRecords()) {
            Integer students = studentService.getStudentCountByCourse(2, record.getSegmentId(), record.getStudyNature(), 0);
            //添加周次信息 todo 是否需要优化显示
            List<SegmentWeek> segmentWeeks = segmentWeekService.list(new LambdaQueryWrapper<SegmentWeek>()
                    .eq(SegmentWeek::getStudyNature, record.getStudyNature())
                    .eq(SegmentWeek::getSegmentId, record.getSegmentId()));
            record.setSegmentWeeks(segmentWeeks);
            record.setStudentNum(students);
        }
        return PagingUtil.formatPageResult(segmentPlanPage);
    }

    @Override
    public TeachingTaskStatistics teachingTaskStatistics(Integer taskId) {
        TeachingTaskStatistics teachingTaskStatistics = new TeachingTaskStatistics();

        List<CoursePlanDto> courseStatistics = courseMapper.courseStatistics(taskId);
        long teachingClassCourseNum = courseStatistics.stream().filter(coursePlanDto -> coursePlanDto.getClassNum() > 0).count();
        //学院分组统计
        Map<String, List<CoursePlanDto>> groupByCollegeId = courseStatistics.stream().collect(Collectors.groupingBy(CoursePlanDto::getCollegeId));
        List<TeachingTaskStatistics.CollegeGroup> courseCollege = groupByCollegeId.entrySet().stream()
                .map(entry -> {
                    TeachingTaskStatistics.CollegeGroup collegeGroup = new TeachingTaskStatistics.CollegeGroup();
                    collegeGroup.setCollegeId(entry.getKey())
                            .setCollegeName(entry.getValue().get(0).getCollegeName())
                            .setNum(entry.getValue().size())
                            .setClassNum(entry.getValue().stream().filter(coursePlanDto -> coursePlanDto.getClassNum() > 0).count())
                            .setNoClassNum(entry.getValue().stream().filter(coursePlanDto -> coursePlanDto.getClassNum() == 0).count())
                            .setTeachingClassNum(entry.getValue().stream().mapToLong(CoursePlanDto::getClassNum).sum());
                    return collegeGroup;
                }).collect(Collectors.toList());

        List<SegmentPlanDto> segmentStatistics = segmentMapper.segmentStatistics(taskId);
        long teachingClassSegmentNum = segmentStatistics.stream().filter(segmentPlanDto -> segmentPlanDto.getClassNum() > 0).count();
        //学院分组统计
        Map<String, List<SegmentPlanDto>> segmentGroupByCollegeId = segmentStatistics.stream().collect(Collectors.groupingBy(SegmentPlanDto::getCollegeId));
        List<TeachingTaskStatistics.CollegeGroup> segmentCollege = segmentGroupByCollegeId.entrySet().stream()
                .map(entry -> {
                    TeachingTaskStatistics.CollegeGroup collegeGroup = new TeachingTaskStatistics.CollegeGroup();
                    collegeGroup.setCollegeId(entry.getKey())
                            .setCollegeName(entry.getValue().get(0).getCollegeName())
                            .setNum(entry.getValue().size())
                            .setClassNum(entry.getValue().stream().filter(segmentPlanDto -> segmentPlanDto.getClassNum() > 0).count())
                            .setNoClassNum(entry.getValue().stream().filter(segmentPlanDto -> segmentPlanDto.getClassNum() == 0).count())
                            .setTeachingClassNum(entry.getValue().stream().mapToLong(SegmentPlanDto::getClassNum).sum())
                    ;
                    return collegeGroup;
                }).collect(Collectors.toList());

        teachingTaskStatistics.setCourseNum(courseStatistics.size())
                .setTeachingClassCourse(teachingClassCourseNum)
                .setNoTeachingClassCourse(courseStatistics.size() - teachingClassCourseNum)
                .setCourseCollegeGroup(courseCollege)
                .setSegmentNum(segmentStatistics.size())
                .setTeachingClassSegment(teachingClassSegmentNum)
                .setNoTeachingClassSegment(segmentStatistics.size() - teachingClassSegmentNum)
                .setSegmentCollegeGroup(segmentCollege);
        return teachingTaskStatistics;
    }
}
